KNN 是 K-nearest neighbor 的縮寫,字面上的意思是『 k 個離最近的鄰居』,k 是一個可調控的整數。
這個算法主要應用在解決分類問題,一個全新的資料點要決定其分類的時候,透過離他最近的 k 個既有資料點的類別大宗來推測這個資料點的類別應該是什麼;也就是說如果一個人的鄰居都拿 iphone 那我推測你也是拿 iphone(誤
以下圖為例,綠色點是一個帶分類的資料點,若『鄰居』的定義是在實線範圍內,則綠色點會被歸類為紅色三角形類別,而若『鄰居』的範圍是定義在虛線範圍內,則綠色點會被歸類為藍色正方形。
img source: wiki
不過在 ES 內,KNN search 的功能只有做到把鄰居找出來,如果需要根據搜尋得到得資訊進行分類預測作業,要再自己實作後續的功能。
ES 提供兩種 KNN 的搜尋:
script_score
定義距離計算的 function 來達成。一樣如名稱所示,會是 Brute-force(窮盡)雖然會是精確的,但就是犧牲 query 速度。大部分的狀況,應該只要使用 Approximate KNN 就可以了,本文謹針對 Approximate KNN 說明。
一個範例的 Approximate KNN query 如下:
POST tmdb_top_rated_movies/_search
{
"query" : {
"knn": {
"field": "overview_vector",
"query_vector": [...],
"k": 10
}
}
}
field
指定要搜尋的 dense_vector 欄位query_vector
是你要搜尋的 vector,假設你要搜尋『黑道家族勾心鬥角』,那就要先把這一段字經過 LLM 轉換成 vector,需要注意的是產生這個 vector 的 LLM 要跟 index 是一樣的,否則就算 dimension 是一樣的,查出來的結果會完全不合理。k
:希望找到幾個鄰居knn search 還有幾個其他的設定參數,都是 optional:
query_vector_builder
: 這個參數和 query_vector 只能擇一設定。這是一個 ES 我覺得很棒的功能,可以直接把要轉 word vector 使用的的 LLM 設定在這,這個 LLM 可以是 hugging-face 上的任何 repo,不過這個功能需要是企業版才能使用,這邊就沒有辦法 demo 了。num_candidates
: 要從每一個 shard 中找多少筆資料來進行 knn,最多 10,000
筆,在 shard 取完之後會 cross shard 再比較一次給出最後的結果。filter
: knn 要搜尋的範圍,例如只想在 vote_count
大於 1,000 的電影資料中搜尋。similarity
: 相似性最低應該要多少。boost
:跟 text search 的 boost 是一樣的功能,會幫最後的搜尋分數呈上一個常數。應該要介於 0 和 1 之間。_name
: 這個 query 的名稱,當你的 query 有很多個條件的時候可以用來辨別這筆資料是符合哪一個條件而被挑出來。那我們就把『黑道家族勾心鬥角』轉換為 word vector 後進行搜尋。
搜尋結果得到的第一筆電影名稱是: 家門之外
,他的描述是:『當爸媽並不容易,尤其是在爸媽想要保護一位充滿好奇心的小浣熊時。在華特迪士尼動畫工作室短片《家門之外》中,這位小浣熊學到了要敞開心胸過日子,即便有可能面臨危險。』
相信你跟我一樣滿頭問號,這個結果不太合理吧,看起來是溫馨的家庭電影啊;另外是搜尋到的前幾名的內容都不太類似,但分數都蠻接近的(0.8~0.9 之間)。
看了一下 model 的說明頁,懷疑幾種可能:
sentence-transformers/all-MiniLM-L6-v2
的限制是 128 個。下一篇來驗證一下可能是什麼問題。